package cn.wolfcode.luowowo.search.service.impl;

import cn.wolfcode.luowowo.search.domain.StrategyTemplate;
import cn.wolfcode.luowowo.search.query.StaticSearchQuery;
import cn.wolfcode.luowowo.search.service.IStrategyTemplateSearchService;
import cn.wolfcode.luowowo.search.vo.StaticsVO;
import cn.wolfcode.luowowo.search.service.repository.StrategyTemplateRepository;
import com.alibaba.dubbo.config.annotation.Service;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.bucket.composite.CompositeAggregation;
import org.elasticsearch.search.aggregations.bucket.composite.CompositeAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.composite.CompositeValuesSourceBuilder;
import org.elasticsearch.search.aggregations.bucket.composite.TermsValuesSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;

import java.util.*;

@Service
public class StrategyTemplateSearchServiceImpl implements IStrategyTemplateSearchService {
    @Autowired
    private StrategyTemplateRepository repository;

    @Autowired
    private ElasticsearchTemplate template;

    //用户的更新或者保存操作
    public void saveOrUpdate(StrategyTemplate strategyTemplate) {
        repository.save(strategyTemplate);//如果没有这个对象就是保存操作,有就是更新操作
    }

    //需求要求: 主题推荐需求
    //1:需要排行, 按照攻略个数排行
    //2:取前面10个
    //3:去除重复目的地
    public List<Map<String, Object>> queryThemeCommends() {
        List<Map<String, Object>> data = new ArrayList<>();
        List<StaticsVO> themes = this.statisGroup("themeId", "themeName", "themeGroup", null);
        //2:取前面10个
        if (themes.size() > 10) {
            themes = themes.subList(0, 10);
        }
        //#########遍历List<StatisVO> 得到每个主题关联目的地集合#####################
        Map<String, Object> map = null;
        for (StaticsVO theme : themes) {
            map = new HashMap<>();
            //左边为主题对象
            map.put("theme", theme);
            //目的地集合 根据主题id查询目的地id,name
            List<StaticsVO> dests = this.getDestByThemeId(theme.getId());
            //右边主题关联目的地集合
            map.put("dests", dests);
            data.add(map);
        }
        return data;
    }

    public List<StaticsVO> statisGroup(String idField, String nameField, String gruopName, BoolQueryBuilder query) {
        //拿到空的sources,以什么字段进行分组,需要显示的名字叫什么    //CompositeValuesSourceBuilder是抽象类,那么只能拿他子类去创建对象设置参数
        List<CompositeValuesSourceBuilder<?>> sources = new ArrayList<>();
        TermsValuesSourceBuilder idSource = new TermsValuesSourceBuilder("id");
        idSource.field(idField);
        TermsValuesSourceBuilder nameSource = new TermsValuesSourceBuilder("name");
        nameSource.field(nameField);
        //最后把这些规则放到sources
        sources.add(idSource);
        sources.add(nameSource);
        //1.要想拿到分组集合对象 composite,第一个参数是以什么分组的(分组查询名称),
        // 2.然后分组之后有哪些字段和内容  存放在sources集合中 直接点进这个类里面拿sources(分组列的集合themeid,themeName)
        CompositeAggregationBuilder aggregationBuilder = new CompositeAggregationBuilder(gruopName, sources);
        //DSL拼接对象
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        builder.addAggregation(aggregationBuilder);
        builder.withPageable(PageRequest.of(0, 1));//去掉头信息
        if (query != null) {
            builder.withQuery(query);
        }
        //执行dsl语句,并且解析结果
        AggregatedPage<StrategyTemplate> page = (AggregatedPageImpl<StrategyTemplate>) repository.search(builder.build());
        CompositeAggregation themeGroup = page.getAggregations().get(gruopName);
        //遍历bucket对象拿到id,和name对应的值 设置对 统计对象中
        List<StaticsVO> themes = new ArrayList<>();
        for (CompositeAggregation.Bucket bucket : themeGroup.getBuckets()) {
            Long id = Long.parseLong(bucket.getKey().get("id").toString());
            String name = bucket.getKey().get("name").toString();
            Long count = bucket.getDocCount();
            themes.add(new StaticsVO(id, name, count));
        }
        //1:需要排行, 按照攻略个数排行
        Collections.sort(themes, new Comparator<StaticsVO>() {
            public int compare(StaticsVO o1, StaticsVO o2) {
                return (int) (o2.getCount() - o2.getCount());//倒叙
            }
        });
        return themes;
    }

    public List<StaticsVO> queryConditionThemes() {
        return this.statisGroup("themeId", "themeName", "themeGroup", null);
    }

    public List<StaticsVO> queryConditionProvince() {
        return this.statisGroup("provinceId", "provinceName", "provinceGroup", null);
    }

    public List<StaticsVO> queryConditionCountries() {
        //排除中国
        BoolQueryBuilder query = QueryBuilders.boolQuery().mustNot(QueryBuilders.termQuery("countryId", 1));
        return this.statisGroup("countryId", "countryName", "countryGroup", query);
    }

    public Page query(StaticSearchQuery qo) {
        if (qo.getType() != null) {
            if (qo.getType() == StaticSearchQuery.CONDITION_TYPE_ABROAD) {
                //国外 countryId=qo.getTypeValue
                return repository.search(QueryBuilders.termQuery("countryId", qo.getTypeValue()), qo.getPageable());
            } else if (qo.getType() == StaticSearchQuery.CONDITION_TYPE_UNABROAD) {
                //国内 provinceId=qo.getTypeValue
                return repository.search(QueryBuilders.termQuery("provinceId", qo.getTypeValue()), qo.getPageable());
            } else if (qo.getType() == StaticSearchQuery.CONDITION_TYPE_THEME) {
                //国内 themeId=qo.getTypeValue
                return repository.search(QueryBuilders.termQuery("themeId", qo.getTypeValue()), qo.getPageable());
            }
        }
        return repository.findAll(qo.getPageable());
    }

    public List<StrategyTemplate> findByDestName(String name) {
        return repository.findByDestName(name);
    }


    public Page query2(StaticSearchQuery qo) {
        NativeSearchQueryBuilder builder2 = new NativeSearchQueryBuilder();
        //对象查询 相当于bool条件,用来逻辑查询
        BoolQueryBuilder builder = QueryBuilders.boolQuery();
        if (qo.getType() == StaticSearchQuery.CONDITION_TYPE_ABROAD) {
            //国外 countryId=qo.getTypeValue
            builder.must(QueryBuilders.termQuery("countryId", qo.getTypeValue()));
        } else if (qo.getType() == StaticSearchQuery.CONDITION_TYPE_UNABROAD) {
            //国内 provinceId=qo.getTypeValue
            builder.must(QueryBuilders.termQuery("provinceId", qo.getTypeValue()));
        } else if (qo.getType() == StaticSearchQuery.CONDITION_TYPE_THEME) {
            //国内 themeId=qo.getTypeValue
            builder.must(QueryBuilders.termQuery("themeId", qo.getTypeValue()));
        }
        return repository.search(builder, qo.getPageable());
    }

    //通过主题id查询目的地的id,name
    private List<StaticsVO> getDestByThemeId(Long themeId) {
        //jap的语法规范findBy属性名  拿对象或者集合
        List<StrategyTemplate> list = repository.findByThemeId(themeId);
        //3:去除重复目的地
        List<StaticsVO> dests = new ArrayList<>();
        //已经存在目的地名
        List<String> names = new ArrayList<>();
        for (StrategyTemplate template : list) {
            if (!names.contains(template.getDestName())) {
                StaticsVO vo = new StaticsVO();
                vo.setId(template.getDestId());
                vo.setName(template.getDestName());
                dests.add(vo);
                //然后把新增的地区名放到集合中进行下次的判断
                names.add(template.getDestName());
            }
        }
        return dests;
    }

}
